﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace Beetle.Silverlight.Controls
{
    public class ArrowLine : System.Windows.Controls.Control
    {
        #region 常量
        internal const string rootElementName = "RootElement";
        internal const string LineElementName = "LineElement";
        internal const string ArrowElementName = "ArrowElement";
        internal const string ArrowStartElementName = "ArrowStartElement";
        internal const string LinePathFigureElementName = "LinePathFigureElement";
        #endregion

        #region 变量

        /// <summary>
        /// 开始点
        /// </summary>
        public PathFigure LinePathFigureElement;
        /// <summary>
        /// 线条路径
        /// </summary>
        public LineSegment lineElement;

        /// <summary>
        /// 箭头路径
        /// </summary>
        public PolyLineSegment arrowElement;
        public PathFigure arrowStartElement;
        #endregion

        #region 属性

        public Canvas RootElement
        {
            get;
            private set;
        }

        /// <summary>
        /// 开始点
        /// </summary>
        public Point StartPoint
        {
            get
            {
                return (Point)this.GetValue(StartPointProperty);
            }
            set
            {
                this.SetValue(StartPointProperty, value);
            }
        }
        public static readonly DependencyProperty StartPointProperty = DependencyProperty.Register(
           "StartPoint",
           typeof(Point),
           typeof(ArrowLine),
           new PropertyMetadata(new Point(10, 10), new PropertyChangedCallback(ReSize)));

        /// <summary>
        /// 终点
        /// </summary>
        public Point EndPoint
        {
            get
            {
                return (Point)this.GetValue(EndPointProperty);
            }
            set
            {
                this.SetValue(EndPointProperty, value);
            }
        }
        public static readonly DependencyProperty EndPointProperty = DependencyProperty.Register(
           "EndPoint",
           typeof(Point),
           typeof(ArrowLine),
           new PropertyMetadata(new Point(100, 10), new PropertyChangedCallback(ReSize)));

        /// <summary>
        /// 宽度
        /// </summary>
        public double StrokeThickness
        {
            get
            {
                return (double)this.GetValue(StrokeThicknessProperty);
            }
            set
            {
                this.SetValue(StrokeThicknessProperty, value);
            }

        }
        public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register(
           "StrokeThickness",
           typeof(double),
           typeof(ArrowLine),
           new PropertyMetadata(2.0, null));

        /// <summary>
        /// 箭头宽度
        /// </summary>
        public double ArrowLineThickness
        {
            get
            {
                return (double)this.GetValue(ArrowLineThicknessProperty);
            }
            set
            {
                this.SetValue(ArrowLineThicknessProperty, value);
            }
        }
        public static readonly DependencyProperty ArrowLineThicknessProperty = DependencyProperty.Register(
           "ArrowLineThickness",
           typeof(double),
           typeof(ArrowLine),
           new PropertyMetadata(2.0, null));

        /// <summary>
        /// 箭头的宽和高
        /// </summary>
        public Size ArrowSize
        {
            get
            {
                return (Size)this.GetValue(ArrowSizeProperty);
            }
            set
            {
                this.SetValue(ArrowSizeProperty, value);
            }

        }
        public static readonly DependencyProperty ArrowSizeProperty = DependencyProperty.Register(
           "ArrowSize",
           typeof(Size),
           typeof(ArrowLine),
           new PropertyMetadata(new Size(4, 8), new PropertyChangedCallback(ReSize)));

        /// <summary>
        /// 虚线
        /// </summary>
        public DoubleCollection StrokeDashArray
        {
            get
            {
                return (DoubleCollection)this.GetValue(StrokeDashArrayProperty);
            }
            set
            {
                this.SetValue(StrokeDashArrayProperty, value);
            }
        }
        public static readonly DependencyProperty StrokeDashArrayProperty = DependencyProperty.Register(
           "StrokeDashArray",
           typeof(DoubleCollection),
           typeof(ArrowLine),
           new PropertyMetadata(null));

        /// <summary>
        /// 箭头可见性
        /// </summary>
        public Visibility ArrowVisibility
        {
            get
            {
                return (Visibility)this.GetValue(ArrowVisibilityProperty);
            }
            set
            {
                this.SetValue(ArrowVisibilityProperty, value);
            }
        }
        public static readonly DependencyProperty ArrowVisibilityProperty = DependencyProperty.Register(
           "ArrowVisibility",
           typeof(Visibility),
           typeof(ArrowLine),
           new PropertyMetadata(Visibility.Visible, null));
        #endregion

        #region 生命周期
        public ArrowLine()
        {
            this.DefaultStyleKey = typeof(Beetle.Silverlight.Controls.ArrowLine);
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            this.arrowElement = (PolyLineSegment)this.GetTemplateChild(Beetle.Silverlight.Controls.ArrowLine.ArrowElementName);
            this.lineElement = (LineSegment)this.GetTemplateChild(Beetle.Silverlight.Controls.ArrowLine.LineElementName);
            this.arrowStartElement = (PathFigure)this.GetTemplateChild(Beetle.Silverlight.Controls.ArrowLine.ArrowStartElementName);
            this.LinePathFigureElement = (PathFigure)this.GetTemplateChild(Beetle.Silverlight.Controls.ArrowLine.LinePathFigureElementName);
            this.RootElement = (Canvas)this.GetTemplateChild(Beetle.Silverlight.Controls.ArrowLine.rootElementName);

            this.SetPosition();
        }
        #endregion

        private static void ReSize(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ArrowLine arrowArcSegment = (ArrowLine)d;
            if (arrowArcSegment.lineElement != null)
                arrowArcSegment.SetPosition();
        }

        public void SetPosition()
        {
            #region 弧线
            this.lineElement.Point = this.EndPoint;
            this.LinePathFigureElement.StartPoint = this.StartPoint;
            #endregion

            #region 箭头
            //切线斜率
            double k;
            k = (this.StartPoint.Y - this.EndPoint.Y) / (this.StartPoint.X - this.EndPoint.X);
            Point centerPoint1, centerPoint2, endPoint11, endPoint12, endPoint21, endPoint22;

            if (double.IsInfinity(k)) //与Y轴平行
            {
                if (this.StartPoint.Y < this.EndPoint.Y)
                {
                    endPoint11 = new Point(-1 * this.ArrowSize.Width + this.EndPoint.X, this.EndPoint.Y - this.ArrowSize.Height);
                    endPoint12 = new Point(this.ArrowSize.Width + this.EndPoint.X, this.EndPoint.Y - this.ArrowSize.Height);
                }
                else
                {
                    endPoint11 = new Point(-1 * this.ArrowSize.Width + this.EndPoint.X, this.EndPoint.Y + this.ArrowSize.Height);
                    endPoint12 = new Point(this.ArrowSize.Width + this.EndPoint.X, this.EndPoint.Y + this.ArrowSize.Height);
                }

                this.arrowStartElement.StartPoint = endPoint11;
                this.arrowElement.Points.Clear();
                this.arrowElement.Points.Add(this.EndPoint);
                this.arrowElement.Points.Add(endPoint12);
            }
            else if (Math.Round(k, 4) == 0)//与X轴平行
            {

                if (this.StartPoint.X < this.EndPoint.X)
                {
                    endPoint11 = new Point(this.EndPoint.X - this.ArrowSize.Height, -1 * this.ArrowSize.Width + this.EndPoint.Y);
                    endPoint12 = new Point(this.EndPoint.X - this.ArrowSize.Height, this.ArrowSize.Width + this.EndPoint.Y);
                }
                else
                {
                    endPoint11 = new Point(this.EndPoint.X + this.ArrowSize.Height, -1 * this.ArrowSize.Width + this.EndPoint.Y);
                    endPoint12 = new Point(this.EndPoint.X + this.ArrowSize.Height, this.ArrowSize.Width + this.EndPoint.Y);
                }

                this.arrowStartElement.StartPoint = endPoint11;
                this.arrowElement.Points.Clear();
                this.arrowElement.Points.Add(this.EndPoint);
                this.arrowElement.Points.Add(endPoint12);
            }
            else
            {
                double xOffset = this.ArrowSize.Height / (Math.Sqrt(1 + k * k));
                double xTemp, yTemp;
                #region 第一个点
                xTemp = this.EndPoint.X + xOffset;
                yTemp = k * (xTemp - this.EndPoint.X) + this.EndPoint.Y;
                centerPoint1 = new Point(Math.Round(xTemp, 4), Math.Round(yTemp, 4));
                #endregion

                #region 第二个点
                xTemp = this.EndPoint.X - xOffset;
                yTemp = k * (xTemp - this.EndPoint.X) + this.EndPoint.Y;
                centerPoint2 = new Point(Math.Round(xTemp, 4), Math.Round(yTemp, 4));
                #endregion

                k = (-1) / k;
                xOffset = this.ArrowSize.Width / (Math.Sqrt(1 + k * k));

                //比较点与起点的距离,取距离近的两点
                double d1 = (centerPoint1.X - this.StartPoint.X) * (centerPoint1.X - this.StartPoint.X) + (centerPoint1.Y - this.StartPoint.Y) * (centerPoint1.Y - this.StartPoint.Y);
                double d2 = (centerPoint2.X - this.StartPoint.X) * (centerPoint2.X - this.StartPoint.X) + (centerPoint2.Y - this.StartPoint.Y) * (centerPoint2.Y - this.StartPoint.Y);

                if (d1 < d2)
                {
                    #region 第一个点对应的两个箭头端点
                    xTemp = centerPoint1.X + xOffset;
                    yTemp = k * (xTemp - centerPoint1.X) + centerPoint1.Y;
                    endPoint11 = new Point(Math.Round(xTemp, 4), Math.Round(yTemp, 4));

                    xTemp = centerPoint1.X - xOffset;
                    yTemp = k * (xTemp - centerPoint1.X) + centerPoint1.Y;
                    endPoint12 = new Point(Math.Round(xTemp, 4), Math.Round(yTemp, 4));
                    #endregion

                    this.arrowStartElement.StartPoint = endPoint11;
                    this.arrowElement.Points.Clear();
                    this.arrowElement.Points.Add(this.EndPoint);
                    this.arrowElement.Points.Add(endPoint12);
                }
                else
                {
                    #region 第二个点对应的两个箭头端点
                    xTemp = centerPoint2.X + xOffset;
                    yTemp = k * (xTemp - centerPoint2.X) + centerPoint2.Y;
                    endPoint21 = new Point(Math.Round(xTemp, 4), Math.Round(yTemp, 4));

                    xTemp = centerPoint2.X - xOffset;
                    yTemp = k * (xTemp - centerPoint2.X) + centerPoint2.Y;
                    endPoint22 = new Point(Math.Round(xTemp, 4), Math.Round(yTemp, 4));
                    #endregion

                    this.arrowStartElement.StartPoint = endPoint21;
                    this.arrowElement.Points.Clear();
                    this.arrowElement.Points.Add(this.EndPoint);
                    this.arrowElement.Points.Add(endPoint22);
                }
            }
            #endregion
        }
    }
}
